//: src/com/silvtar/net/ftp/SSFtpClient.java
/* 
 * Created by 朴晟宁 <piaosn@gmail.com> on 4/21/2013. 
 * Copyright (c) 2013 朴晟宁. All rights reserved.
 * 
 * 
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program;
 * 
 * *********************************************************************
 * 
 * Modify History:
 * Date        Version    Description
 * 5/2/2013    0.1        Create the class.
 * 5/3/2013    0.1.1      It become easy to use now.
 */
package com.silvtar.net.ftp;

import java.io.IOException;
import java.util.LinkedList;
import com.silvtar.io.StdOut;
import com.silvtar.sync.model.SSAnalyzer;
import com.silvtar.sync.model.SSException;
import com.silvtar.sync.model.SSTreeNode;

/**
 * FTP传输。负责根据分析结果通过FTP传输传输文件
 * 
 * @author 朴晟宁/Silvtar
 * @author piaosn@gmail.com
 * @version 0.1.1
 */
public class FtpTransporter {

    private SSFtpClient            ftpClient  = null;

    private LinkedList<SSTreeNode> outQueue   = null; // 传出队列

    private LinkedList<SSTreeNode> inQueue    = null; // 传入队列

    private String                 localRoot  = null; // 本地根目录

    private String                 remoteRoot = null; // 远程根目录

    private boolean                useMd5     = true; // 传输后是否使用MD5校验传输结果

    // ---------------------------- 构造方法 ---------------------------
    /**
     * 传输器通过分析器获得源地址以及目的地址
     * 
     * @param analyzer
     *            分析器
     * @param localRoot
     *            本地同步根目录
     * @param remoteRoot
     *            远程同步根目录
     */
    public FtpTransporter(SSAnalyzer analyzer, String localRoot,
            String remoteRoot) {

        outQueue = (LinkedList<SSTreeNode>) analyzer.getOutQueue().clone();
        inQueue = (LinkedList<SSTreeNode>) analyzer.getInQueue().clone();

        this.localRoot = localRoot;
        this.remoteRoot = remoteRoot;

        ftpClient = new SSFtpClient();

        if (analyzer.isUseMd5()) {
            useMd5 = true;
        } else {
            useMd5 = false;
        }
    }

    /**
     * 配置函数，传输前需调用本函数配置FTP客户端
     * 
     * @param ipAddr
     *            FTP服务器的IP地址
     * @param port
     *            FTP服务的端口号
     * @param username
     *            用户名
     * @param password
     *            密码
     */
    public void config(String ipAddr, int port, String username, String password) {

        ftpClient.config(ipAddr, port, username, password);

    }

    /**
     * 开始传输
     * 
     * @throws SSException
     * @throws IOException
     */
    public void startTransport() throws SSException {
        ftpClient.connect();
        ftpClient.login();
        if (localRoot == null || remoteRoot == null) {
            throw new SSException("没有设置同步目录");
        }

        // 从local传输到remote
        while (!outQueue.isEmpty()) {
            SSTreeNode currentTreeNode = outQueue.pop();
            upload(currentTreeNode);
        }

        // 从remote传输到local
        while (!inQueue.isEmpty()) {
            SSTreeNode currentTreeNode = inQueue.pop();
            download(currentTreeNode);
        }
        ftpClient.disconnect();
        StdOut.println("FTPTransport Down!");
    }

    /**
     * 输出两条队列，与SSTree中的同名函数一致
     */
    public void print() {

        StdOut.println("OUT_QUEUE:  size = " + outQueue.size() + "\n");
        while (!outQueue.isEmpty()) {
            StdOut.println("  " + outQueue.pop().getName());
        }

        StdOut.println();
        StdOut.println("IN_QUEUE:  size = " + inQueue.size() + "\n");
        while (!inQueue.isEmpty()) {
            StdOut.println("  " + inQueue.pop().getName());
        }
    }

    /**
     * 将文件节点上传到FTP服务器
     * 
     * @param currentFile_TN
     *            要上传的文件节点
     */
    private void upload(SSTreeNode currentFile_TN) {
        String localFile_S = localRoot + currentFile_TN.getRelativePath();
        String remoteFile_S = remoteRoot + currentFile_TN.getRelativePath();

        if (!currentFile_TN.isDir()) {
            ftpClient.upload(remoteFile_S, localFile_S);

        } else {
            // 如果目录不存在，则新建。
            if (!ftpClient.exist(remoteFile_S)) {
                try {
                    ftpClient.mkdir(remoteFile_S);
                } catch (Exception e) {
                    StdOut.println("Create " + remoteFile_S + "Error!");
                }
            }

            // 获取所有子文件
            for (int i = 0; i < currentFile_TN.getChild().size(); i++) {
                upload(currentFile_TN.getChild().get(i));
            }
        }
    }

    /**
     * 将文件节点下载到本地
     * 
     * @param currentFile_TN
     *            要下载的文件节点
     */
    private void download(SSTreeNode currentFile_TN) {
        String localFile_S = localRoot + currentFile_TN.getRelativePath();
        String remoteFile_S = remoteRoot + currentFile_TN.getRelativePath();

        if (!currentFile_TN.isDir()) {
            ftpClient.download(remoteFile_S, localFile_S);

        } else {
            // 如果目录不存在，则新建。
            if (!ftpClient.exist(remoteFile_S)) {
                try {
                    ftpClient.mkdir(remoteFile_S);
                } catch (Exception e) {
                    StdOut.println("Create " + remoteFile_S + "Error!");
                }
            }

            // 获取所有子文件
            for (int i = 0; i < currentFile_TN.getChild().size(); i++) {
                download(currentFile_TN.getChild().get(i));
            }
        }
    }

}
